#include "entity.h"
#include "animation.h"
#include "objmanager.h"
#include "util.h"
#include "controller.h"
#include "hgeheader.h"
#include "scene.h"
#include "game.h"
#include "map.h"

Entity::Entity()
{
	mID = INVALID_ID;
	mAnim = 0;
	mX = mY = 0;
	mLayer = 10;
	mController = 0;
	mProto = 0;
	mCurAction = 0;
	mMoveSpeed = 10.0f;
	mDirection = Direction_RIGHT;
	mFaceDirection = Direction_RIGHT;
	mHp = 0;
	mMaxHp = 0;
	mNoDmgTimer = 0;
}

Entity::~Entity()
{
	SAFE_DELETE(mAnim);
}

void Entity::update( int diff )
{
	mLastCollision = getCollsionBox();
	mLastX = mX;
	mLastY = mY;
	if( mCurAction->name == "move" )
	{
		float movedistance = mMoveSpeed*float(diff)/1000.0f;
		if( mDirection == Direction_LEFT)
		{
			mX = mX - movedistance;
		}
		else if( mDirection == Direction_RIGHT)
		{
			mX = mX + movedistance;
		}
		else if( mDirection == Direction_UP)
		{
			mY = mY - movedistance;
		}
		else if( mDirection == Direction_DOWN)
		{
			mY = mY + movedistance;
		}
	}

	if( mController )
	{
		mController->Update();
	}
	
	if( mAnim )
	{
		mAnim->Update(diff);
		if( mAnim->mCurAnim->IsEnd() )
		{
			doAction(defaultaction);
		}
	}
	if( mNoDmgTimer > 0 )
		mNoDmgTimer -= diff;
	Truncate( mNoDmgTimer, 0, mNoDmgTimer );
	checkCollision();
	checkWeaponCollision();
}

void Entity::render()
{
	render( mX, mY );
}

void Entity::render( int x, int y, int w, int h )
{
	if( mAnim )
	{
		mAnim->Render( x, y, w, h, mLayer );
		renderBoundBox();
		renderHP();
	}
}

void Entity::init( EntityDef *def )
{
	if( !def )
		return;
	mProto = def;
	mMoveSpeed = def->movespeed;
	mHp = def->maxhp;
	mMaxHp = def->maxhp;
	mAnim = AnimManager::Instance().Load( def->animname.c_str() );
	doAction(defaultaction);
	setDirection( Direction_RIGHT );
	setFaceDirection( Direction_RIGHT );
}

gcn::Rectangle Entity::getCollsionBox()
{
	gcn::Rectangle ret =  mAnim->GetCollisionBox();
	ret.x += mX;
	ret.y += mY;
	return ret;
}

gcn::Rectangle Entity::getWeaponBox()
{
	gcn::Rectangle ret =  mAnim->GetWeaponBox();
	ret.x += mX;
	ret.y += mY;
	return ret;
}

gcn::Rectangle Entity::getBoundBox()
{
	gcn::Rectangle ret =  mAnim->GetBoundBox();
	ret.x += mX;
	ret.y += mY;
	return ret;
}

void Entity::setController( Controller *ctrl )
{
	if( ctrl == 0 )
		return;
	mController = ctrl;
	mController->SetEntity(this);
}

void Entity::doAction( std::string actionname , bool forcereset)
{
	if( mCurAction && mCurAction->name == actionname && forcereset == false )
	{
		return;
	}
	Action *action = mProto->GetAction( actionname );
	if( action == 0 )
		return;
	if( mAnim )
	{
		mCurAction = action;
		mAnim->Play( action->anim );
	}
}

void Entity::setDirection( int direction )
{
	mDirection = direction;
}

void Entity::setFaceDirection( int direction )
{
	mAnim->SetDirection( direction );
	mFaceDirection = direction;
}

void Entity::renderBoundBox()
{
	gcn::Rectangle box = getBoundBox();
	box.x += mapviewarea.x;
	box.y += mapviewarea.y;
	renderRectangle( box.x, box.y, box.x+box.width, box.y+box.height, 0xffff0000 );
	box = getCollsionBox();
	box.x += mapviewarea.x;
	box.y += mapviewarea.y;
	renderRectangle( box.x, box.y, box.x+box.width, box.y+box.height, 0xff00ff00 );
	box = getWeaponBox();
	box.x += mapviewarea.x;
	box.y += mapviewarea.y;
	renderRectangle( box.x, box.y, box.x+box.width, box.y+box.height, 0xff0000ff );
}

void Entity::renderHP()
{
	gcn::Rectangle box = getBoundBox();
	box.x += mapviewarea.x;
	box.y += mapviewarea.y;
	int hpheight = 5;
	renderRectangle( box.x, box.y-hpheight, box.x+box.width, box.y, 0xff000000 );
	float hpratio = float(mHp)/float(mMaxHp);
	renderRectangle( box.x+1, box.y-hpheight+1, box.x+hpratio*(box.width-2), box.y-2, 0xffff0000, true );
}

void Entity::checkWeaponCollision()
{
	gcn::Rectangle weapon = getWeaponBox();
	if( weapon.width == 0 || weapon.height == 0 )
		return;
	int footy = getFootY();
	for( EntityMap::iterator iter = Game::state.scene->mUpdateObjs.begin(); iter != Game::state.scene->mUpdateObjs.end(); iter++ )
	{
		Entity *e = iter->second;
		if( this == e )
			continue;
		if( mLayer != e->mLayer )
			continue;
		gcn::Rectangle collision = e->getCollsionBox();
		//int anotherfooty = e->getFootY();
		//if( abs(footy - anotherfooty) > 10 )
		//	continue;
		if( weapon.isIntersecting( collision) )
		{
			e->damage( this, 5 );
		}
	}
}

void Entity::checkCollision()
{
	gcn::Rectangle box = getCollsionBox();
	if( box.width == 0 || box.height == 0 )
		return;
	//int footy = getFootY();
	for( EntityMap::iterator iter = Game::state.scene->mUpdateObjs.begin(); iter != Game::state.scene->mUpdateObjs.end(); iter++ )
	{
		Entity *e = iter->second;
		if( this == e )
			continue;
		if( mLayer != e->mLayer )
			continue;
		gcn::Rectangle collision = e->getCollsionBox();
		//int anotherfooty = e->getFootY();
		//if( abs(footy - anotherfooty) > 2 )
		//	continue;
		if( box.isIntersecting( collision ) )
		{
			mX = mLastX;
			mY = mLastY;
			box = getCollsionBox();
		}
	}
	MapLayer *layer = Game::state.curmap->GetLayer( mLayer );
	for( int i=box.x; i<box.x+box.width+Game::state.tileunitsize; i=i+Game::state.tileunitsize )
	{
		for( int j=box.y; j<box.y+box.height+Game::state.tileunitsize; j=j+Game::state.tileunitsize )
		{
			int x = i/Game::state.tileunitsize;
			int y = j/Game::state.tileunitsize;
			if( layer->GetTerrain(x,y) != 0 )
			{
				mX = mLastX;
				mY = mLastY;
				box = getCollsionBox();
				break;
			}
		}
	}
}

int Entity::damage( Entity *src, int value )
{
	if( mNoDmgTimer > 0 )
		return 0;
	mHp -= value;
	Truncate( mHp, 0, mMaxHp );
	mNoDmgTimer = 1000;
	return value;
}

int Entity::getFootY()
{
	gcn::Rectangle r = getBoundBox();
	return r.y + r.height;
}
